package com.yx.test3d.model;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.GLES30;

import com.yx.test3d.bean.Obj3D;
import com.yx.test3d.utils.LogUtils;
import com.yx.test3d.utils.ShaderUtil;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.List;

import static android.opengl.GLES20.GL_COLOR_ATTACHMENT0;
import static android.opengl.GLES20.GL_DEPTH_ATTACHMENT;
import static android.opengl.GLES20.GL_DEPTH_BUFFER_BIT;
import static android.opengl.GLES20.GL_DEPTH_COMPONENT;
import static android.opengl.GLES20.GL_DEPTH_COMPONENT16;
import static android.opengl.GLES20.GL_FLOAT;
import static android.opengl.GLES20.GL_FRAMEBUFFER;
import static android.opengl.GLES20.GL_FRAMEBUFFER_COMPLETE;
import static android.opengl.GLES20.GL_NEAREST;
import static android.opengl.GLES20.GL_NONE;
import static android.opengl.GLES20.GL_REPEAT;
import static android.opengl.GLES20.GL_RGBA4;
import static android.opengl.GLES20.GL_TEXTURE0;
import static android.opengl.GLES20.GL_TEXTURE_2D;
import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
import static android.opengl.GLES20.GL_UNSIGNED_INT;
import static android.opengl.GLES20.glActiveTexture;
import static android.opengl.GLES20.glBindFramebuffer;
import static android.opengl.GLES20.glBindTexture;
import static android.opengl.GLES20.glCheckFramebufferStatus;
import static android.opengl.GLES20.glClear;
import static android.opengl.GLES20.glGenFramebuffers;
import static android.opengl.GLES20.glGenRenderbuffers;
import static android.opengl.GLES20.glGenTextures;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glTexParameterf;
import static android.opengl.GLES20.glUniform1i;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glVertexAttribPointer;
import static android.opengl.GLES20.glViewport;
import static android.opengl.GLES30.GL_ARRAY_BUFFER;
import static android.opengl.GLES30.GL_COLOR_BUFFER_BIT;
import static android.opengl.GLES30.GL_STATIC_DRAW;
import static android.opengl.GLES30.GL_TRIANGLES;
import static android.opengl.GLES30.glBindBuffer;
import static android.opengl.GLES30.glBindVertexArray;
import static android.opengl.GLES30.glBufferData;
import static android.opengl.GLES30.glDrawArrays;
import static android.opengl.GLES30.glEnableVertexAttribArray;
import static android.opengl.GLES30.glFramebufferTexture2D;
import static android.opengl.GLES30.glGenBuffers;
import static android.opengl.GLES30.glGenVertexArrays;
import static android.opengl.GLES30.glTexImage2D;
import static android.opengl.GLES30.glUseProgram;

public class TestFboModel extends Model {
/*

    private static final String TAG = Cube.class.getSimpleName();
    protected FloatBuffer vertexBuffer;
    protected FloatBuffer colorBuffer;
    String cubeVert = "#version 300 es\n" +
            "in vec3 v_position;\n" +
            "out vec3 f_color;\n" +
            "uniform mat4 mat_model;\n" +
            "uniform mat4 mat_view;\n" +
            "uniform mat4 mat_proj;\n" +
            "void main()\n" +
            "{\n" +
            "    gl_Position = mat_proj * mat_view * mat_model * vec4(v_position, 1.0);\n" +
            "    f_color = v_position.zxy;\n" +
            "}";

    String cubeFrag = "#version 300 es\n" +
                        "in vec3 f_color;\n" +
                        "out vec4 FragColor;\n" +
            "void main()\n" +
            "{    \n" +
                        "    FragColor = vec4(f_color,1.0);\n" +
            "}";
    String imageVert = "#version 300 es\n" +
            "in vec3 position;\n" +
            "in vec2 texCoords;\n" +
            "out vec2 TexCoords;\n" +
            "void main()\n" +
            "{\n" +
            "    gl_Position = vec4(position,1.0f);\n" +
            "    TexCoords = texCoords;\n" +
            "}";
    String imageFrag = "#version 300 es\n" +
            "in vec2 TexCoords;\n" +
            "out vec4 color;\n" +
            "\n" +
            "uniform sampler2D screenTexture;\n" +
            "\n" +
            "void main()\n" +
            "{\n" +
            //            "    color = texture(screenTexture, TexCoords);\n" +

            "    float depthValue = texture(screenTexture, TexCoords).r;\n" +
            "    color = vec4(vec3(depthValue), 1.0);\n" +
            "}";
    private List<Obj3D> objectList = new ArrayList<>();
    private int imageProgram;
    private int cubeProgram;
    private int[] cubeVaos;
    private int[] cubeVbos;
    private int[] imageVao = new int[1];
    private int[] imageVbo = new int[2];
    private int[] imageFbo = new int[1];
    private int[] imageTexture = new int[2];
    //顶点坐标
    private float[] sPos = {
            -1.0f, 1.0f, 0f,    //左上角
            -1.0f, -1.0f, 0f,   //左下角
            1.0f, 1.0f, 0f,     //右上角
            1.0f, -1.0f, 0f,     //右下角
    };

    //纹理坐标
    private float[] sCoord = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            1.0f, 1.0f,
    };

    public TestFboModel(List<Obj3D> data) {
        objectList = new ArrayList<>();
        objectList.addAll(data);

        setVertex(sPos);
        setVertexColor(sCoord);
    }


    @Override
    public void setMatrix(float[] mMatrix, float[] vMatrix, float[] pMatrix) {
        super.setMatrix(mMatrix, vMatrix, pMatrix);
    }

    @Override
    public void onCreate(Context context) {
        cubeProgram = ShaderUtil.createProgram(cubeVert, cubeFrag);
        imageProgram = ShaderUtil.createProgram(imageVert, imageFrag);

        initCubeVAO();
        initImageVAO();
        createDepathBuffer();
    }


    @Override
    public void onDraw() {

        glUseProgram(cubeProgram);
        glUniformMatrix4fv(glGetUniformLocation(cubeProgram, "mat_model"), 1, false, mMatrix, 0);
        glUniformMatrix4fv(glGetUniformLocation(cubeProgram, "mat_view"), 1, false, vMatrix, 0);
        glUniformMatrix4fv(glGetUniformLocation(cubeProgram, "mat_proj"), 1, false, pMatrix, 0);
        glViewport(0, 0, 1024, 1024);

//        glBindFramebuffer(GL_FRAMEBUFFER, imageFbo[0]);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        for (int i = 0; i < objectList.size(); i++) {
            drawWithVAO(objectList.get(i), objectList.get(i).modelVao);
        }

        glBindFramebuffer(GL_FRAMEBUFFER, GLES20.GL_NONE);
*/
/*
        glUseProgram(imageProgram);
        glViewport(0, 0, width, height);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glActiveTexture(GL_TEXTURE0);//激活纹理
        glBindTexture(GL_TEXTURE_2D, imageTexture[1]);//绑定纹理
        glUniform1i(glGetUniformLocation(imageProgram, "screenTexture"), 0);

        drawImageVAO();*//*


    }

    @Override
    public void onDestroy() {
    }

    public void setVertex(float[] vertex) {
        vertexBuffer = ByteBuffer.allocateDirect(vertex.length * FLOAT_SIZE)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer().put(vertex);
        vertexBuffer.flip();
    }

    public void setVertexColor(float[] color) {
        colorBuffer = ByteBuffer.allocateDirect(color.length * FLOAT_SIZE)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer().put(color);
        colorBuffer.flip();
    }

    private void initCubeVAO() {
        cubeVaos = new int[objectList.size()];
        cubeVbos = new int[objectList.size()];
        glGenVertexArrays(cubeVaos.length, cubeVaos, 0);
        glGenBuffers(cubeVbos.length, cubeVbos, 0);
        for (int i = 0; i < objectList.size(); i++) {
            Obj3D objectData = objectList.get(i);
            objectData.modelVao = cubeVaos[i];
            LogUtils.i("vao  " + cubeVaos[i]);

            glBindVertexArray(cubeVaos[i]);
            glBindBuffer(GL_ARRAY_BUFFER, cubeVbos[i]);
            glBufferData(GL_ARRAY_BUFFER, objectData.position.capacity() * 4, objectData.position, GL_STATIC_DRAW);
            glVertexAttribPointer(glGetAttribLocation(cubeProgram, "v_position"), 3, GL_FLOAT, false, 0, 0);
            glEnableVertexAttribArray(glGetAttribLocation(cubeProgram, "v_position"));

            glBindVertexArray(GL_NONE);

        }

    }

    private void drawWithVAO(Obj3D objectData, int vao) {
        LogUtils.i(" draw vao  " + vao);
        glBindVertexArray(vao);
        glDrawArrays(GL_TRIANGLES, 0, objectData.position.limit() / 3);
        glBindVertexArray(GL_NONE);
    }

    private void initImageVAO() {

        GLES30.glGenVertexArrays(1, imageVao, 0);
        GLES30.glGenBuffers(2, imageVbo, 0);

        GLES30.glBindVertexArray(imageVao[0]);
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, imageVbo[0]);
        GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES30.GL_STATIC_DRAW);
        glVertexAttribPointer(glGetAttribLocation(imageProgram, "position"), 3, GLES30.GL_FLOAT, false, 3 * 4, 0);
        GLES30.glEnableVertexAttribArray(glGetAttribLocation(imageProgram, "position"));

        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, imageVbo[1]);
        GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, colorBuffer.capacity() * 4, colorBuffer, GLES30.GL_STATIC_DRAW);
        glVertexAttribPointer(glGetAttribLocation(imageProgram, "texCoords"), 2, GLES30.GL_FLOAT, false, 2 * 4, 0);
        GLES30.glEnableVertexAttribArray(glGetAttribLocation(imageProgram, "texCoords"));

        GLES30.glBindVertexArray(0);

    }

    private void drawImageVAO() {
        GLES30.glBindVertexArray(imageVao[0]);
        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
        GLES30.glBindVertexArray(0);
    }


    private void createDepathBuffer() {
        //生成帧缓冲
        glGenFramebuffers(1, imageFbo, 0);
        glBindFramebuffer(GL_FRAMEBUFFER, imageFbo[0]);

*/
/*        int[] rbo = new int[1];
        glGenRenderbuffers(1, rbo, 0);
        glBindRenderbuffer(GL_RENDERBUFFER, rbo[0]);
        glRenderbufferStorage(GL_RENDERBUFFER, GLES30.GL_RGBA8, 1024, 1024);
        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rbo[0]);
        glBindRenderbuffer(GL_RENDERBUFFER, 0);*//*


        //生成纹理缓冲
        glGenTextures(2, imageTexture, 0);
        glBindTexture(GL_TEXTURE_2D, imageTexture[0]);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, 1024, 1024, 0, GL_RGBA4, GL_UNSIGNED_BYTE, null);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, imageTexture[0], 0);

        glBindTexture(GL_TEXTURE_2D, imageTexture[1]);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, null);
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, imageTexture[1], 0);
        glBindTexture(GL_TEXTURE_2D, 0);


        int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
        LogUtils.i(" framebuffer生成 " + status);
        if (status != GL_FRAMEBUFFER_COMPLETE) {
            // framebuffer生成失败
            LogUtils.i(" framebuffer生成 " + status);
        }

        // 切换到默认帧缓冲
        glBindFramebuffer(GL_FRAMEBUFFER, 0);
    }

*/

}
